package cn.xhh.dailyreview.client;

import cn.xhh.dailyreview.client.utils.ClientUtil;
import cn.xhh.dailyreview.client.utils.MsgCallback;
import cn.xhh.dailyreview.client.utils.Result;

import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.KeyListener;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.util.DateWrapper;
import com.extjs.gxt.ui.client.util.DateWrapper.Unit;
import com.extjs.gxt.ui.client.widget.HorizontalPanel;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.Text;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.NumberField;
import com.extjs.gxt.ui.client.widget.layout.HBoxLayoutData;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;

public class OverviewPanel {
	
	static final String[] DAYS = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

	/** the base row index in the calendar FlexTable */
	private static final int CALENDAR_ROW_BASE = 2;
	
	private final DailyReview dailyReview;
	private VerticalPanel overview;
	private VerticalPanel userManage;

	/** current date of the calendar */
	private DateWrapper currDate;

	private FlexTable calendar;
	private NumberField year;
	private NumberField month;

	public OverviewPanel(DailyReview dailyReview) {
		this.dailyReview = dailyReview;
	}

	public void show() {
		configOptions(dailyReview);
		showOverviewPanel();
	}

	private void showOverviewPanel() {
		if (overview == null)
			initOverview();
		dailyReview.showPanel(overview);
	}

	/** Show the User Management panel for administrator */
	private void showUserManagePanel() {
		if (userManage == null)
			initUserManage();
		dailyReview.showPanel(userManage);
	}
	
	private void initOverview() {
		overview = new VerticalPanel();
		overview.setSize("95%", "95%");
		overview.setSpacing(5);
		overview.setHorizontalAlignment(VerticalPanel.ALIGN_CENTER);
		
		HorizontalPanel title = new HorizontalPanel();
		title.setSpacing(10);
		title.add(new Text("Review Overview"));
		title.add(new Button("Fill Today", new SelectionListener<ButtonEvent>() {
			@Override
			public void componentSelected(ButtonEvent ce) {
				// TODO Auto-generated method stub
				ClientUtil.flash("Not implemented");
			}
		})); // show this button if today's review has not been filled
		overview.add(title);
		
		calendar = new FlexTable();
		calendar.setCellPadding(5);
		calendar.setWidth("500px");
		FlexCellFormatter cellFormater = calendar.getFlexCellFormatter();
		
		currDate = new DateWrapper(); // default: today
		
		HorizontalPanel yearMonth = new HorizontalPanel();
		yearMonth.setSpacing(3);
		yearMonth.setHeight(30);
		
		Button lastMonth = new Button("<");
		lastMonth.setWidth(30);
		lastMonth.addSelectionListener(new SelectionListener<ButtonEvent>() {
			@Override
			public void componentSelected(ButtonEvent ce) {
				currDate = currDate.add(Unit.MONTH, -1);
				updateCalendar();
			}
		});
		yearMonth.add(lastMonth);
		
		yearMonth.addText("&nbsp;&nbsp;");
		
		year = new NumberField();
		year.setWidth(70);
		year.setSelectOnFocus(true);
		year.setValue(currDate.getFullYear());
		yearMonth.add(year);
		
		month = new NumberField();
		month.setWidth(50);
		month.setSelectOnFocus(true);
		month.setValue(currDate.getMonth() + 1);
		yearMonth.add(month);
		
		yearMonth.addText("&nbsp;&nbsp;");
		
		Button nextMonth = new Button(">");
		nextMonth.setWidth(30);
		nextMonth.addSelectionListener(new SelectionListener<ButtonEvent>() {
			@Override
			public void componentSelected(ButtonEvent ce) {
				currDate = currDate.add(Unit.MONTH, 1);
				updateCalendar();
			}
		});
		yearMonth.add(nextMonth);
		
		calendar.setWidget(0, 0, yearMonth);
		cellFormater.setHorizontalAlignment(0, 0, HasHorizontalAlignment.ALIGN_CENTER);
		cellFormater.setColSpan(0, 0, 7);
		
		for (int dayIdx=0; dayIdx<7; dayIdx++) {
			Label day = new Label(DAYS[dayIdx]);
			day.setHeight("25px");
			day.addStyleName("calendar-day-title");
			day.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
			calendar.setWidget(1, dayIdx, day);
			cellFormater.setHorizontalAlignment(1, dayIdx, HasHorizontalAlignment.ALIGN_CENTER);
		}
		
		updateCalendar();
		
		overview.add(calendar);
		
		KeyListener listenerLoadOverview = new KeyListener() {
			@Override
			public void componentKeyPress(ComponentEvent event) {
				if (event.getKeyCode() != KeyCodes.KEY_ENTER)
					return;
				
				DateWrapper today = new DateWrapper();
				int vYear = (year.getValue() == null) ? today.getFullYear() : year.getValue().intValue();
				if (vYear < 0) {
					ClientUtil.flash("Invalid year.");
					year.focus();
					return;
				}
				int vMonth = (month.getValue() == null) ? today.getMonth()+1 : month.getValue().intValue();
				
				currDate = new DateWrapper(vYear, vMonth - 1, 1);
				updateCalendar();
			}
		};
		year.addKeyListener(listenerLoadOverview);
		month.addKeyListener(listenerLoadOverview);
		
	}
	
	private void initUserManage() {
		// TODO
	}

	private void updateCalendar() {
		int baseIdx = currDate.getFirstDayOfMonth().getDay();
		FlexCellFormatter cellFormater = calendar.getFlexCellFormatter();
		
		year.setValue(currDate.getFullYear());
		month.setValue(currDate.getMonth() + 1);
		
		while (calendar.getRowCount() > CALENDAR_ROW_BASE)
			calendar.removeRow(CALENDAR_ROW_BASE);
		
		for (int dateIdx=1; dateIdx<=currDate.getDaysInMonth();dateIdx++) {
			int idx = dateIdx + baseIdx - 1;
			int row = idx / 7 + CALENDAR_ROW_BASE;
			int col = idx % 7;
			
			Text dateWidget = new Text(String.valueOf(dateIdx));
			dateWidget.setHeight("25px");
			dateWidget.addStyleName("calendar-date");
			dateWidget.addStyleName(col==0 || col==6 ? "calendar-weekend" : "calendar-weekday");
			cellFormater.setAlignment(row, col,  HasHorizontalAlignment.ALIGN_CENTER, 
					HasVerticalAlignment.ALIGN_BOTTOM);
			calendar.setWidget(row, col, dateWidget);
		}
	}

	private void configOptions(final DailyReview dailyReview) {
		LayoutContainer options = dailyReview.getOptions();
		options.removeAll();

		final Text userInfo = new Text();
		userInfo.addStyleName("login-options");
		userInfo.setStyleAttribute("textAlign", "right");
		userInfo.setWidth(300);
		options.add(userInfo, new HBoxLayoutData(0, 10, 0, 0));

		Hyperlink lnkSettings = new Hyperlink();
		lnkSettings.setText("Settings");
		lnkSettings.addStyleName("login-options");
		lnkSettings.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				ClientUtil.flash("Not implemented");
			}
		});
		options.add(lnkSettings, new HBoxLayoutData(0, 10, 0, 0));
		
		Hyperlink lnkUser = new Hyperlink();
		lnkUser.setText("User Management");
		lnkUser.addStyleName("login-options");
		lnkUser.setVisible(false);
		lnkUser.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				showUserManagePanel();
			}
		});
		options.add(lnkSettings, new HBoxLayoutData(0, 10, 0, 0));

		Hyperlink lnkLogout = new Hyperlink();
		lnkLogout.setText("Logout");
		lnkLogout.addStyleName("login-options");
		lnkLogout.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				dailyReview.showLoading();
				ClientUtil.getService().logout(new MsgCallback(dailyReview) {
					public void onSuccess(Result result) {
						clearLoading();
						dailyReview.showLogin();
					}
				});
			}
		});
		options.add(lnkLogout);
		
		if (dailyReview.getEmail() == null) {
			userInfo.setText("Hi");
			ClientUtil.getService().getUserEmail(new AsyncCallback<String>() {
				@Override
				public void onFailure(Throwable caught) {
					MsgCallback.doFailure(caught);
				}
				@Override
				public void onSuccess(String email) {
					if (email != null) {
						userInfo.setText("Hi, " + email);
						dailyReview.setEmail(email);
					}
				}
			});
		} else {
			userInfo.setText("Hi, " + dailyReview.getEmail());
		}
	}
	
}
